package cn.donting.jme.core.state;

import cn.donting.jme.EditorContent;
import cn.donting.jme.JmeApplication;
import cn.donting.jme.ioc.Bean;
import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.material.Material;
import com.jme3.material.Materials;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.debug.Grid;
import com.jme3.util.BufferUtils;

import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

@Bean
public class EditorGridState extends AbstractEditorAppState {
    private static final int GRID_SIZE_LINES=100;
    Geometry gridGeometry;
    GridMesh gridMesh;
    @Override
    public void initialize(AppStateManager stateManager, JmeApplication app) {
        gridGeometry = new Geometry("Grid");
        Material material = new Material(app.getAssetManager(), Materials.UNSHADED);
        gridGeometry.setMaterial(material);
        material.setColor("Color", ColorRGBA.White.mult(0.2f));
        gridMesh = new GridMesh(GRID_SIZE_LINES, GRID_SIZE_LINES, 1);
        gridGeometry.setMesh(gridMesh);
        EditorContent.getJmeApplication().getEditorNode().attachChild(gridGeometry);
    }

    @Override
    public void update(float tpf) {
        Camera camera = EditorContent.getJmeApplication().getEditorCamera();

        Vector3f location = camera.getLocation();
        float absY = Math.abs(location.y);
        int dist = (int) (absY / 10)+1;
        if (gridMesh.lineDist!=dist) {
            gridMesh = new GridMesh(GRID_SIZE_LINES, GRID_SIZE_LINES, dist);
            gridGeometry.setMesh(gridMesh);
        }

        int offsetX=(int)location.x/gridMesh.lineDist*gridMesh.lineDist;
        int offsetZ=(int)location.z/gridMesh.lineDist*gridMesh.lineDist;

        gridGeometry.setLocalTranslation(offsetX,0,offsetZ);

    }


    private static class GridMesh extends com.jme3.scene.Mesh {

        private int lineDist;


        public GridMesh(int xLines, int yLines, int lineDist) {
            this.lineDist=lineDist;
            xLines -= 2;
            yLines -= 2;
            int lineCount = xLines + yLines + 4;
            FloatBuffer fpb = BufferUtils.createFloatBuffer(6 * lineCount);
            ShortBuffer sib = BufferUtils.createShortBuffer(2 * lineCount);

            float xLineLen = (yLines + 1) * lineDist;
            float yLineLen = (xLines + 1) * lineDist;
            int curIndex = 0;

            // add lines along X
            for (int i = 0; i < xLines + 2; i++) {
                float y = (i) * lineDist;

                // positions
                fpb.put(0 - (xLines * lineDist) / 2).put(0).put(y - yLines * lineDist / 2);
                fpb.put(xLineLen - (xLines * lineDist) / 2).put(0).put(y - yLines * lineDist / 2);

                // indices
                sib.put((short) (curIndex++));
                sib.put((short) (curIndex++));
            }

            // add lines along Y
            for (int i = 0; i < yLines + 2; i++) {
                float x = (i) * lineDist;

                // positions
                fpb.put(x - (xLines * lineDist) / 2).put(0).put(0 - yLines * lineDist / 2);
                fpb.put(x - (xLines * lineDist) / 2).put(0).put(yLineLen - yLines * lineDist / 2);

                // indices
                sib.put((short) (curIndex++));
                sib.put((short) (curIndex++));
            }

            fpb.flip();
            sib.flip();

            setBuffer(VertexBuffer.Type.Position, 3, fpb);
            setBuffer(VertexBuffer.Type.Index, 2, sib);

            setMode(Mode.Lines);

            updateBound();
            updateCounts();
            setStatic();
        }

    }

    public static void main(String[] args) {
        new GridMesh(10, 10, 1);
    }
}
